الهدف الرئيسي من هذا التحليل هو فهم أعمق لسلوك المستخدم وتفضيلاته. نسعى لتحديد أنواع المحتوى الذي يتابعه، بالإضافة إلى معرفة البلد الذي يقيم فيه. هذا سيمكننا من التعرف على أهم البودكاستات الرائجة في منطقته الجغرافية.
وبناءً على هذه المعلومات، نقوم بتطوير اقتراحات مخصصة للبودكاستات التي تتناسب تمامًا مع اهتمامات المستخدم. الهدف هو تعزيز تجربته وتشجيعه على الاستمرار في مشاهدة المحتوى المفضل لديه، مما يضمن له تجربة ممتعة.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
# Load datasets
users_df = pd.read_csv('users.csv')
episodes_df = pd.read_csv('episodes.csv')
listens_df = pd.read_json('listens.json')
# Data dimensions summary
def print_dimensions(df, name):
print(f"{name}: {df.shape[0]} rows, {df.shape[1]} columns")
print_dimensions(users_df, "users_df")
print_dimensions(episodes_df, "episodes_df")
print_dimensions(listens_df, "listens_df")
users_df: 20 rows, 4 columns episodes_df: 30 rows, 3 columns listens_df: 100 rows, 3 columns
# Print column names for all DataFrames
print("users_df columns:", users_df.columns.tolist())
print("episodes_df columns:", episodes_df.columns.tolist())
print("listens_df columns:", listens_df.columns.tolist())
users_df columns: ['user_id', 'age', 'gender', 'country'] episodes_df columns: ['episode_id', 'title', 'category'] listens_df columns: ['user_id', 'episode_id', 'duration_seconds']
# Printing formatted DataFrame information
print("users_df Information:")
print("="*50)
print(users_df.info())
print("="*50)
print("episodes_df Information:")
print("="*50)
print(episodes_df.info())
print("="*50)
print("listens_df Information:")
print("="*50)
print(listens_df.info())
users_df Information: ================================================== <class 'pandas.core.frame.DataFrame'> RangeIndex: 20 entries, 0 to 19 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 user_id 20 non-null int64 1 age 20 non-null int64 2 gender 20 non-null object 3 country 20 non-null object dtypes: int64(2), object(2) memory usage: 768.0+ bytes None ================================================== episodes_df Information: ================================================== <class 'pandas.core.frame.DataFrame'> RangeIndex: 30 entries, 0 to 29 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 episode_id 30 non-null int64 1 title 30 non-null object 2 category 30 non-null object dtypes: int64(1), object(2) memory usage: 848.0+ bytes None ================================================== listens_df Information: ================================================== <class 'pandas.core.frame.DataFrame'> RangeIndex: 100 entries, 0 to 99 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 user_id 100 non-null int64 1 episode_id 100 non-null int64 2 duration_seconds 100 non-null int64 dtypes: int64(3) memory usage: 2.5 KB None
تُقدّم الدالة info نظرة شاملة على بنية البيانات، بما في ذلك أسماء الأعمدة، أنواع بياناتها، وعدد القيم غير المفقودة في كل عمود. من خلال تحليل مخرجات info للبيانات التي لدينا، نلاحظ أن عدد القيم متساوٍ في جميع الأعمدة ويساوي العدد الكلي للاسطر. هذا يشير إلى عدم وجود أي قيم مفقودة ضمن مجموعات البيانات التي نعمل عليها، مما يقلل من الحاجة لمعالجة البيانات المفقودة في هذه المرحلة.
إضافة إلى ذلك، فقد تأكدنا من أن أنواع البيانات المخصصة لكل عمود تتوافق تمامًا مع طبيعة المعلومات التي يمثلها العمود. هذا يعني أن الأعمدة الرقمية مُعرّفة كأرقام، والأعمدة النصية كـ "كائنات" (strings)، وهكذا. هذا التحقق الأولي يضمن أن البيانات جاهزة للتحليل دون الحاجة لتغيير أنواع البيانات، مما يسهل سير العمل ويقلل من الأخطاء المحتملة.
# Handle missing values
print("\nMISSING VALUES ANALYSIS")
print("="*50)
print("users_df missing values:\n", users_df.isnull().sum())
print("\nepisodes_df missing values:\n", episodes_df.isnull().sum())
print("\nlistens_df missing values:\n", listens_df.isnull().sum())
MISSING VALUES ANALYSIS ================================================== users_df missing values: user_id 0 age 0 gender 0 country 0 dtype: int64 episodes_df missing values: episode_id 0 title 0 category 0 dtype: int64 listens_df missing values: user_id 0 episode_id 0 duration_seconds 0 dtype: int64
لقد تأكدت بشكل أعم من عدم وجود أي قيم مفقودة في البيانات. قمت بحساب عدد القيم المفقودة في كل عمود، وكانت النتيجة صفر في جميع الأعمدة. هذا يؤكد أن مجموعات البيانات لدي كاملة.
users_df.describe()
| user_id | age | |
|---|---|---|
| count | 20.00000 | 20.000000 |
| mean | 10.50000 | 40.200000 |
| std | 5.91608 | 11.349009 |
| min | 1.00000 | 19.000000 |
| 25% | 5.75000 | 31.500000 |
| 50% | 10.50000 | 42.000000 |
| 75% | 15.25000 | 46.500000 |
| max | 20.00000 | 59.000000 |
تحتوي هذه البيانات على معلومات حول العمر، الجنس، والمدينة. بالتركيز على العمر كقيمة عددية، استخدمنا الدالة describe لفهم توزيعه. لقد وجدنا أن الأعمار تتراوح بين 19 و 59 عامًا، وهو نطاق مناسب تمامًا للمشاهدين المستهدفين لحلقات البودكاست.
علاوة على ذلك، يبلغ المتوسط الحسابي للعمر 40 عامًا، وهو ما يُعد عمرًا مثاليًا لمشاهدي البودكاست، مما يشير إلى أن غالبية المستخدمين ضمن الفئة العمرية التي تستهلك هذا النوع من المحتوى. هذه النتائج تؤكد عدم وجود أي قيم متطرفة (Outliers) غير منطقية في بيانات العمر.
بعد أن انتهينا من تحليل بيانات العمر، لننتقل الآن إلى استكشاف توزيع بيانات الجنس والمدينة ضمن نفس مجموعة البيانات.
def plot_value_counts_pie(df, column_name):
data_counts = df[column_name].value_counts()
print(data_counts)
print('\n')
plt.pie(data_counts, labels=data_counts.index,autopct='%1.1f%%')
plt.title(column_name)
plt.show()
plot_value_counts_pie(users_df, 'gender')
female 11 male 9 Name: gender, dtype: int64
تشير البيانات إلى أن الرجال أقل مشاهدة لحلقات البودكاست مقارنة بالإناث.
plot_value_counts_pie(users_df, 'country')
Jordan 6 Egypt 5 Saudi Arabia 4 Morocco 4 UAE 1 Name: country, dtype: int64
الأردن هو البلد الذي يضم أكبر عدد من مشاهدي البودكاست.
episodes_df.describe(include=['object'])
| title | category | |
|---|---|---|
| count | 30 | 30 |
| unique | 30 | 6 |
| top | Episode 19 | Sports |
| freq | 1 | 9 |
نلاحظ أن البيانات المتوفرة لا تحتوي على عناوين وصفية للحلقات، بل تقتصر على أرقام متسلسلة من "Episode 1" إلى "Episode 30". لو كانت هناك عناوين أو أوصاف محددة للحلقات، لتمكّنا من تطبيق معالجة اللغات الطبيعية (NLP) لاستخلاص معلومات قيمة حول محتوى كل حلقة. هذا كان سيفتح آفاقًا مستقبلية لـ توقع عناوين البودكاست المقترحة للمستخدم بناءً على العناوين التي يشاهدها.
أما فيما يخص عمود التصنيفات (category)، فتشير البيانات الحالية إلى أن الحلقات الأكثر شيوعًا لدينا هي حلقات الرياضة، والتي يبلغ عددها 9 حلقات.
plot_value_counts_pie(episodes_df, 'category')
Sports 9 Society 8 News 6 Politics 3 Religion 2 Technology 2 Name: category, dtype: int64
مخطط لتصنيفات الحلقات المتاحة وعددها
listens_df.describe().round(2)
| user_id | episode_id | duration_seconds | |
|---|---|---|---|
| count | 100.00 | 100.00 | 100.00 |
| mean | 10.76 | 15.50 | 669.00 |
| std | 5.98 | 9.65 | 689.42 |
| min | 1.00 | 1.00 | 0.00 |
| 25% | 6.00 | 7.00 | 60.00 |
| 50% | 11.00 | 14.00 | 300.00 |
| 75% | 16.00 | 25.00 | 1500.00 |
| max | 20.00 | 30.00 | 1800.00 |
في تحليلنا للبيانات، وعلى الرغم من أن جميع الأعمدة تتكون من أرقام، إلا أن تركيزنا ينصب على عمود المدة الزمنية (duration_seconds)، مع استبعاد العمليات الإحصائية على أعمدة الـ ID.
بناءً على بيانات الاستماع المتوفرة (listens_df)، لاحظنا ما يلي:
تُعتبر المدة القصوى البالغة 30 دقيقة طبيعية ومنطقية تمامًا في سياق حلقات البودكاست. أما بالنسبة لأدنى مدة، فإن وجود "صفر ثانية" يشير إلى أن هذه المدة غير منطقية كاستماع حقيقي لحلقة بودكاست. بينما يمكن أن تكون الحلقات القصيرة جدًا - مثل دقيقة واحدة - بمثابة مقاطع دعائية، مقتطفات سريعة، أو إعلانات. تتناسب الحلقات الأطول مع المحتوى التعليمي أو الحوارات المتعمقة.
بشكل عام، تتراوح مدة البودكاستات الشائعة كما يلي:
الخلاصة: بما أن أقصى مدة (30 دقيقة) تقع ضمن النطاق الطبيعي لمختلف أنواع البودكاست، فلا توجد حاجة لإزالتها كـ "قيمة متطرفة". ومع ذلك، فإن القيمة "صفر ثانية" تُعتبر قيمة غير منطقية ولا تمثل استماعًا فعليًا لحلقة، ولذلك يجب رفضها. سنعتمد على مدة الدقيقة الواحدة كحد أدنى مقبول للاستماع الفعلي لحلقات البودكاست. هذه القيم تمثل مدد استماع واقعية ومتوقعة.
سأقوم بحذف جميع حلقات البودكاست التي تبلغ مدتها صفر ثانية, مع إضافة عمود للدقائق
clean_listens = listens_df[listens_df['duration_seconds'] > 0]
clean_listens['duration_minutes'] = (clean_listens['duration_seconds'] / 60).astype(int)
plot_value_counts_pie(clean_listens, 'duration_minutes')
5 20 1 17 30 15 25 14 15 12 2 9 Name: duration_minutes, dtype: int64
لنلقِ نظرة على المدة الزمنية الأكثر مشاهدة ضمن البودكاستات. يوضح المخطط أن أكثر مدة للمشاهدة هي 5 دقائق، مما يشير إلى أن معظم الأشخاص توقفوا عند هذه الدقيقة ولم يكملوا الاستماع للحلقة.
# Merge datasets
merged_df = clean_listens.merge(users_df, on='user_id', how='left')
full_df = merged_df.merge(episodes_df, on='episode_id', how='left')
full_df.head(10)
| user_id | episode_id | duration_seconds | duration_minutes | age | gender | country | title | category | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 16 | 30 | 60 | 1 | 24 | female | Saudi Arabia | Episode 30 | Sports |
| 1 | 6 | 8 | 120 | 2 | 59 | male | Morocco | Episode 8 | Sports |
| 2 | 6 | 13 | 60 | 1 | 59 | male | Morocco | Episode 13 | Society |
| 3 | 6 | 27 | 1500 | 25 | 59 | male | Morocco | Episode 27 | News |
| 4 | 17 | 9 | 1500 | 25 | 21 | male | Saudi Arabia | Episode 9 | Sports |
| 5 | 14 | 23 | 300 | 5 | 19 | female | Morocco | Episode 23 | Sports |
| 6 | 15 | 6 | 60 | 1 | 42 | male | UAE | Episode 6 | Society |
| 7 | 12 | 27 | 1800 | 30 | 52 | female | Jordan | Episode 27 | News |
| 8 | 3 | 1 | 60 | 1 | 42 | male | Saudi Arabia | Episode 1 | Religion |
| 9 | 12 | 24 | 120 | 2 | 52 | female | Jordan | Episode 24 | Society |
full_df.shape
(87, 9)
category_listens = full_df.groupby('category')['duration_minutes'].sum().sort_values(ascending=False)
category_listens
category Sports 388 Society 312 News 205 Religion 94 Technology 65 Politics 51 Name: duration_minutes, dtype: int32
# Create bar chart visualization
category_listens.plot(kind='bar', color='skyblue')
plt.title('Total Listening Duration by Category', fontsize=14)
plt.ylabel('Total Listening minutes', fontsize=12)
plt.xlabel('Category', fontsize=12)
plt.xticks(rotation=45) # Rotate labels for better readability
plt.grid(axis='y', linestyle='--', alpha=0.7) # Add subtle gridlines
plt.tight_layout() # Ensure proper spacing
plt.show()
تُعدّ الرياضة من أكثر الفئات استماعًا
# Calculate average listening duration in minutes
male_mean = full_df[full_df['gender'] == 'male']['duration_minutes'].mean()
female_mean = full_df[full_df['gender'] == 'female']['duration_minutes'].mean()
# Calculate the absolute difference
difference = abs(male_mean - female_mean)
# Format and print the difference
print("="*50)
print("Gender-Based Listening Duration Difference")
print("="*50)
print(f"Average listening duration (males): {male_mean:.2f} minutes")
print(f"Average listening duration (females): {female_mean:.2f} minutes")
print("-"*50)
print(f"Difference: {difference:.2f} minutes")
print("="*50)
# Add interpretation
if female_mean > male_mean:
print("\nFemale listeners spend approximately {:.2f} more minutes per session.".format(difference))
else:
print("\nMale listeners spend approximately {:.2f} more minutes per session.".format(difference))
================================================== Gender-Based Listening Duration Difference ================================================== Average listening duration (males): 10.44 minutes Average listening duration (females): 15.14 minutes -------------------------------------------------- Difference: 4.69 minutes ================================================== Female listeners spend approximately 4.69 more minutes per session.
# Calculate number of episodes per user
user_episode_counts = full_df.groupby('user_id')['episode_id'].count()
# Calculate average
average_episodes = user_episode_counts.mean()
print(f"Average episodes per user: {average_episodes:.1f} episodes")
Average episodes per user: 4.6 episodes
fig = px.histogram(full_df, x="country", y="category",
color='category', barmode='group',
histfunc='count',
width=800, height=400)
fig.show()
يهدف هذا المخطط إلى فهم تفضيلات الفئات حسب البلد، مما يعد خطوة أساسية في تحليل سلوك المستخدم واقتراح محتوى مناسب له.
لقد كشف تحليلنا لتوزيع الفئات عبر البلدان المختلفة عن اهتمامات متباينة:
الأردن اهتمامًا كبيرًا بفئة Society .المملكة العربية السعودية ومصر اهتمامًا ملحوظًا بفئة الرياضة.تساعدنا هذه الرؤى على تقديم اقتراحات بودكاستات مخصصة تتناسب مع الاهتمامات المحلية لكل دولة، مما يعزز تجربة المستخدم ويزيد من تفاعله مع المحتوى.
def fun_1(x):
xx = []
min_frequently = full_df['duration_minutes'][(full_df['user_id'] == x)]
xx = list(min_frequently.mode())
return xx
full_df['minute_frequently'] = full_df.apply(lambda x : fun_1(x['user_id']),axis = 1)
dic_minute_frequently=pd.DataFrame(dict(zip(full_df['category'] , full_df['minute_frequently'])).items(),columns = ['category','minute_frequently'])
dic_minute_frequently
| category | minute_frequently | |
|---|---|---|
| 0 | Sports | [1] |
| 1 | Society | [5] |
| 2 | News | [1, 15, 30] |
| 3 | Religion | [30] |
| 4 | Technology | [2] |
| 5 | Politics | [5, 15, 30] |
إنشاء جدول يلخص المدد الزمنية الأكثر شيوعًا للمشاهدة لكل فئة من فئات المحتوى. هذا يساعد في فهم:
هل يميل مستمعو الرياضة، على سبيل المثال، إلى مشاهدة حلقات أقصر أو أطول مقارنة بمستمعي فئة "Society"؟ ما هو النطاق الزمني الأمثل للحلقات التي تنتمي إلى كل فئة؟ يمكن أن تكون هذه المعلومات مفيدة جدًا للمساعدة في تحديد المحتوى الأمثل لاقتراحه للمستخدمين، ليس فقط بناءً على الفئة المفضلة لديهم، بل أيضًا بناءً على المدة الزمنية المفضلة لتلك الفئة.
fig = px.strip(full_df, x=full_df['category'], y=full_df['age'],color='category')
fig.show()
فهم العلاقة بين فئات البودكاست التي يشاهدها المستخدمون وأعمارهم.
يُساعد هذا التحليل في بناء فهم أعمق لجمهور كل فئة، مما يفيد في استهداف المحتوى بشكل أفضل وتقديم توصيات أكثر دقة بناءً على عمر المستخدم واهتماماته.
fig = px.histogram(full_df, x="category", y="gender",
color='gender', barmode='group',
histfunc='count',
width=700, height=300)
fig.show()
توزيع إلى تحليل توزيع مشاهدات البودكاست حسب الفئة والجنس.
يُساعد هذا التحليل في فهم تفضيلات المحتوى بناءً على الجنس، مما يُعد مفيدًا لتخصيص المحتوى واستهداف الجمهور بشكل أكثر فعالية عند تقديم اقتراحات البودكاست.
def recommend_episodes(user_id: int, listens_df: pd.DataFrame, episodes_df: pd.DataFrame):
# Get the episodes listened by the user
user_listens = listens_df[listens_df['user_id'] == user_id]
# Get the episode IDs the user has listened to
listened_episode_ids = user_listens['episode_id'].unique()
# Get the categories of the episodes the user has listened to
listened_categories = episodes_df[episodes_df['episode_id'].isin(listened_episode_ids)]['category']
# Count the occurrences of each category
category_counts = listened_categories.value_counts()
# Get the top 3 categories
top_categories = category_counts.head(3).index.tolist()
# Recommend episodes from the top categories that the user hasn't listened to yet
recommendations = episodes_df[episodes_df['category'].isin(top_categories) &
~episodes_df['episode_id'].isin(listened_episode_ids)]
# Return the top 3 recommended episodes
return recommendations.head(3)
# Example usage:
# Assuming listens_df, episodes_df are already defined DataFrames
recommended_episodes = recommend_episodes(user_id=19, listens_df=listens_df, episodes_df=episodes_df)
recommended_episodes.head()
| episode_id | title | category | |
|---|---|---|---|
| 2 | 3 | Episode 3 | Society |
| 5 | 6 | Episode 6 | Society |
| 7 | 8 | Episode 8 | Sports |
recommend_episodes)¶تهدف هذه الدالة إلى تقديم توصيات مخصصة لحلقات بودكاست جديدة للمستخدمين، بناءً على اهتماماتهم السابقة. تُركز الفكرة على تحليل ما استمع إليه المستخدم بالفعل، ومن ثم اقتراح محتوى مشابه لم يقم بمشاهدته بعد.
إليك كيفية عمل العملية خطوة بخطوة:
فهم ما شاهده المستخدم:
تبدأ الدالة بتحديد جميع الحلقات التي استمع إليها المستخدم المحدد (user_id).
تحديد الفئات المفضلة للمستخدم: باستخدام قائمة الحلقات التي استمع إليها المستخدم، تقوم الدالة بعد ذلك بتحديد الفئات (categories) التي تنتمي إليها تلك الحلقات. على سبيل المثال، إذا استمع المستخدم لعدة حلقات رياضية وحلقات دين، فسيتم تسجيل كلتا الفئتين.
تحديد الفئات الأكثر اهتمامًا: بعد جمع جميع الفئات التي شاهدها المستخدم، تقوم الدالة بحساب عدد مرات ظهور كل فئة. ثم تحدد أكثر 3 فئات مشاهدة من قبل هذا المستخدم. هذه الفئات تمثل اهتماماته الرئيسية.
اقتراح حلقات جديدة من الفئات المفضلة:
في الخطوة الأخيرة، تبحث الدالة في جميع الحلقات المتاحة (episodes_df) عن تلك التي تنتمي إلى الفئات الثلاثة المفضلة لدى المستخدم. الأهم من ذلك، أنها تستبعد أي حلقات يكون المستخدم قد استمع إليها بالفعل.
تقديم أفضل التوصيات: تعرض الدالة أفضل 3 حلقات تم العثور عليها ضمن هذه المعايير كتوصيات نهائية للمستخدم.
بهذه الطريقة، نضمن أن التوصيات ذات صلة مباشرة باهتمامات المستخدم المحددة، مما يزيد من احتمالية تفاعله مع المحتوى الجديد والاستمتاع به.
def recommend_episodes_2(user_id: int, listens_df, episodes_df):
# Calculate total listens for each episode
episode_listens = listens_df.groupby('episode_id').size().reset_index(name='total_listens')
episodes_with_popularity = pd.merge(episodes_df, episode_listens, on='episode_id', how='left')
# Get episodes the user has already listened to
listened_episodes = listens_df[listens_df['user_id'] == user_id]['episode_id'].unique()
# Get user's listened categories and their counts
user_listens = listens_df[listens_df['user_id'] == user_id]
if not user_listens.empty:
user_listens_with_cat = pd.merge(user_listens, episodes_df, on='episode_id')
category_counts = user_listens_with_cat.groupby('category').size().reset_index(name='count')
top_categories = category_counts.sort_values('count', ascending=False)['category'].tolist()
else:
top_categories = []
# Prepare list for recommendations
recommendations = []
# Recommend from top categories
for category in top_categories:
if len(recommendations) >= 3:
break
# Get top episodes in this category not listened by the user
category_episodes = episodes_with_popularity[
(episodes_with_popularity['category'] == category) &
(~episodes_with_popularity['episode_id'].isin(listened_episodes))
]
# Exclude already recommended episodes
if recommendations:
recommended_ids = [ep['episode_id'] for ep in recommendations]
category_episodes = category_episodes[~category_episodes['episode_id'].isin(recommended_ids)]
# Sort by popularity and select top remaining
category_episodes = category_episodes.sort_values(['total_listens', 'episode_id'], ascending=[False, False])
num_needed = min(3 - len(recommendations), len(category_episodes))
if num_needed > 0:
top_episodes = category_episodes.head(num_needed)
for _, row in top_episodes.iterrows():
recommendations.append({
'episode_id': row['episode_id'],
'title': row['title'],
'category': row['category']
})
# Fill remaining slots with globally popular episodes
if len(recommendations) < 3:
all_episodes = episodes_with_popularity[
~episodes_with_popularity['episode_id'].isin(listened_episodes)
]
if recommendations:
recommended_ids = [ep['episode_id'] for ep in recommendations]
all_episodes = all_episodes[~all_episodes['episode_id'].isin(recommended_ids)]
all_episodes = all_episodes.sort_values(['total_listens', 'episode_id'], ascending=[False, False])
num_needed = 3 - len(recommendations)
if num_needed > 0:
top_episodes = all_episodes.head(num_needed)
for _, row in top_episodes.iterrows():
recommendations.append({
'episode_id': row['episode_id'],
'title': row['title'],
'category': row['category']
})
return pd.DataFrame(recommendations).head(3)
recommended_episodes = recommend_episodes_2(user_id=19, listens_df=listens_df, episodes_df=episodes_df)
recommended_episodes.head()
| episode_id | title | category | |
|---|---|---|---|
| 0 | 19 | Episode 19 | Politics |
| 1 | 29 | Episode 29 | Sports |
| 2 | 8 | Episode 8 | Sports |
recommend_episodes_2)¶تهدف هذه الدالة إلى تقديم توصيات ذكية ومُحسّنة لحلقات البودكاست للمستخدمين. تعتمد الفكرة العامة على الجمع بين تفضيلات المستخدم الفردية (based on categories) وشعبية الحلقات العامة لتقديم توصيات أكثر فعالية وتنوعًا.
إليك كيفية عمل العملية خطوة بخطوة:
حساب شعبية الحلقات: تُحسب هذه الدالة أولاً العدد الإجمالي لمرات الاستماع لكل حلقة في جميع البيانات المتاحة. هذا يمنحنا مقياسًا لشعبية كل حلقة بشكل عام، بغض النظر عن المستخدم.
تحديد الحلقات التي استمع إليها المستخدم بالفعل:
تُحدد الدالة جميع معرفات الحلقات التي استمع إليها المستخدم المحدد (user_id)، لضمان عدم اقتراح حلقات سبق له مشاهدتها.
تحديد الفئات المفضلة للمستخدم (مع الترتيب): تُحلل الدالة الفئات التي استمع إليها المستخدم في الماضي، وتُحصي تكرار كل فئة. ثم تقوم بترتيب هذه الفئات تنازليًا حسب عدد مرات الاستماع، مما يعطينا الفئات الأكثر تفضيلاً للمستخدم.
اقتراح من الفئات المفضلة (مع الأخذ بالشعبية):
ملء التوصيات بحلقات شائعة عالميًا (إذا لزم الأمر): إذا لم تتمكن الدالة من العثور على 3 توصيات من الفئات المفضلة للمستخدم (على سبيل المثال، إذا كان المستخدم قد استمع بالفعل إلى جميع الحلقات الشائعة في فئاته المفضلة، أو إذا كانت فئاته المفضلة تحتوي على عدد قليل من الحلقات)، فإنها تلجأ إلى اقتراح الحلقات الأكثر شعبية عالميًا (لم يستمع إليها المستخدم بعد) لملء العدد المطلوب من التوصيات (حتى 3).
إرجاع التوصيات النهائية: تُرجع الدالة أفضل 3 توصيات في شكل إطار بيانات يحتوي على معرف الحلقة، العنوان، والفئة.
recommend_episodes)¶هناك عدة فروقات جوهرية تجعل recommend_episodes_2 أكثر تعقيدًا وقوة:
دمج عامل الشعبية (Popularity):
ترتيب الفئات المفضلة:
التعامل مع السيناريوهات التي لا توجد فيها توصيات كافية:
تجنب تكرار التوصيات بشكل أفضل:
باختصار، recommend_episodes_2 هي نظام توصية أكثر تطوراً يوازن بين التفضيلات الشخصية للمستخدم والجاذبية العامة (الشعبية) للمحتوى، ويوفر توصيات أكثر اكتمالاً وموثوقية.
إيمان البلخي